/*  BEAMOUT.C  -------------------------------------------------------------

	The transmitting side of the BEAMER system. It sits in the back-
	ground permanently and uses link paste to drag in to memory and
	then beam it all out the port.

	Effectively complete.

	-------------------------------------------------------------------------  */


#include <p_std.h>
#include <p_gen.h>
#include <p_sys.h>
#include <p_file.h>
#include <p_keyb.h>
#include <p_graf.h>
#include <p_screen.h>
#include <p_serial.h>
#include <epoc.h>

#include <lp.h>

#include <wlib.h>
#include <hwif.h>


#define CONTROL_O				15

#define TX_BUF_MAX_LEN		0x1000 - 5


GLREF_D TEXT		*	DatCommandPtr;

LOCAL_D UINT			MainWid;
LOCAL_D INT				ret;                       /*  General use return value  */
LOCAL_D INT				i;                              /*  General use counter  */

LOCAL_D VOID		*	sch;                       /*  Channel to beamer device  */

LOCAL_D HANDLE			WsrvHandle;             /*  Handle of the Window Server  */
LOCAL_D HANDLE			ioSem;                             /*  Our io semaphore  */
LOCAL_D HANDLE			srvPid;              /*  Handle of the LinkPaste server  */

LOCAL_D WORD			sStat;                      /*  Status word for p_logon  */

LOCAL_D TEXT			TxBuf[TX_BUF_MAX_LEN];          /*  The transmit buffer  */
LOCAL_D UINT			TxBufLen;                 /*  Length of transmit buffer  */



LOCAL_C INT Check(INT val, TEXT *msg)              /*  General purpose check  */
    {
    TEXT		buf[50];

    if (val >= 0)
        return val;
    p_atos(&buf[0],"Error : %s",msg);
    p_notifyerr(val,&buf[0],0,0,0);
    p_exit(0);
    }


	
LOCAL_C INT PasteIn(UINT arg1, UINT arg2)     /*  Get data from paste server  */
	{
	INT						SigCount;
	WORD						MStat;
	INT						lret;

	p_msendreceivea(srvPid, TY_LINKSV_STEP, &arg1, &MStat);

	SigCount = 0;                 /*  Initialise the count of 'stray' signals  */

	FOREVER
		{
		p_iowait();                                                /*  Wait...  */
		if (sStat != E_FILE_PENDING)                       /*  Server has died  */
			{
			p_mcancel();                                 /*  Cancel the request  */
			p_waitstat(&MStat);                          /*  Consume the signal  */
			lret = E_GEN_RECEIVER;                              /*  No receiver  */
			break;
			}
		else if (MStat != E_FILE_PENDING)               /*  Result is returned  */
			{
			lret = MStat;
			break;
			}
		else
			SigCount++;                                  /*  Count the 'strays'  */
		}

	if (SigCount)
		p_signaln(ioSem, SigCount);                      /*  Put back 'strays'  */

	return lret;
	}
	
	
LOCAL_C INT BringData(VOID)
	{
	ULONG						fmt;
	ULONG					*	pfmt;

	union
		{
		ULONG					l;
		UWORD					w[2];
		} arg;

	TEXT						namebuf[P_FNAMESIZE];



	pfmt = &fmt;

	Check(srvPid = p_msendreceivew(WsrvHandle,
												SY_LINK_PASTE,
												&pfmt), "asking for formats");
	if (!srvPid)                             /*  No server to bring data from  */
		{
		return E_FILE_NXIST;                                     /*  So say so  */
		}

	if (fmt & DF_LINK_TABTEXT)                            /*  Support TABTEXT  */
		{
		arg.l = DF_LINK_TABTEXT;
		}

	p_pname(srvPid, &namebuf[0]);              /*  Find out who the server is  */

	p_logona(srvPid, &sStat);        /*  Request notification of server death  */

	ret = PasteIn(arg.w[0], arg.w[1]);                /*  Request a rendering  */

	if (ret == 0)
		{
		FOREVER
			{
			ret = PasteIn((UINT)&TxBuf[0], sizeof(TxBuf));    /*  Get some data  */
			if (ret < 0)
				{
				if (ret == E_FILE_EOF)
					{
					ret = 0;
					}
				break;
				}
			TxBufLen = ret;
			PasteIn((UINT)&TxBuf[0], 0);        /*  Tell server we are all done  */
			break;
			}
		}

	if (sStat == E_FILE_PENDING)        /*  We are still logged on the server  */
		{
		p_logoffa(srvPid);                   /*  Cancel the death notification  */
		p_waitstat(&sStat);                             /*  Consume the signal  */
		}

	Check(ret, "At end of BringData()");
	}
	
	
LOCAL_C VOID BeamData(VOID)
	{
	INT						len;

	p_scpy(&TxBuf[TxBufLen], "+++");                /*  Tag on the terminator  */
	TxBufLen += 3;                           /*  Buffer is now 3 bytes longer  */
	len = TxBufLen;                                /*  Local copy of TxBufLen  */

	Check(p_open(&sch, "TTY.BEM:X", 0xffff), "opening TTY.BEM:X");
	Check(p_iow4(sch, P_FWRITE, &TxBuf[0], &len), "BeamData: p_iow4: 1");
	Check(p_close(sch), "closing TTY.BEM:X");
	}
	
	
LOCAL_C VOID GoToBack(VOID)
	{
	wClientPosition(WS_LAST_CLIENT_POSITION, 0);
	wFlush();
	}
	
	

LOCAL_C VOID CancelCaptureKey(VOID)
	{
	Check(wCancelCaptureKey(CONTROL_O,
			W_SHIFT_MODIFIER | W_CTRL_MODIFIER,
			W_SHIFT_MODIFIER | W_CTRL_MODIFIER | W_PSION_MODIFIER),
			"cancelling captured key");

	}
	
	

LOCAL_C VOID UnloadPDD(VOID)
	{
	p_devdel("TTY.BEM", E_PDD);                  /*  Remove the beamer device  */
	}


LOCAL_C VOID CleanUpAndQuit()
	{
	UnloadPDD();
	CancelCaptureKey();
	p_exit(0);
	}



LOCAL_C VOID ProcessSystemCommand(VOID)              /*  Listen to the shell  */
	{
	TEXT				buf[P_FNAMESIZE + 2];

	wGetCommand((UBYTE *)&buf[0]);
	if (buf[0] == 'X')
		{
		CleanUpAndQuit();
		p_exit(0);
		}
	}

	
LOCAL_C VOID MainLoop(VOID)                              /*  Main event loop  */
	{
	WMSG_KEY					key;


	FOREVER
		{
		uGetKey(&key);                             /*  Get a key synchronously  */
		if (key.keycode & W_EVENT_KEY)                    /*  If it's an event  */
			{
			switch (key.keycode)
				{
				case CONS_EVENT_FOREGROUND:               /*  Came to foreground  */
					GoToBack();                /*  Go straight back to background  */
					break;
				case CONS_EVENT_BACKGROUND:                       /*  Do nothing  */
				case CONS_EVENT_COMMAND:                /*  The shell has spoken  */
					ProcessSystemCommand();                    /*  Obey the shell  */
				}
			}
		else if ((key.modifiers &
						W_SHIFT_MODIFIER | W_CTRL_MODIFIER) ==
						(W_SHIFT_MODIFIER | W_CTRL_MODIFIER) &&
						key.keycode == (CONTROL_O))            /*  Is it our key ?  */
			{
			if ((BringData()) >= 0)                      /*  Paste in some data  */
				{
				BeamData();                                          /*  Beam it  */
				p_sleep(10L);                              /*  Wait a short time  */
				p_sound(5,320);                       /*  Beep to say it is done  */
				}
			}
		}
	}
	

LOCAL_C VOID CaptureKey(VOID)                        /*  Capture our hot key  */
	{
	Check(wCaptureKey(CONTROL_O,
			W_SHIFT_MODIFIER | W_CTRL_MODIFIER,
			W_SHIFT_MODIFIER | W_CTRL_MODIFIER | W_PSION_MODIFIER),
			"capturing key");
	}
	
	
LOCAL_C VOID LoadPDD(VOID)                        /*  Load the device driver  */
	{
    TEXT				buf[P_FNAMESIZE];

#ifdef DEBUG
	p_scpy(&buf[0], "loc::m:\\app\\beamv1.pdd");
#else
    p_fparse("BEAMV1.PDD", DatCommandPtr, &buf[0], NULL);
#endif
    ret = p_loadpdd(&buf[0]);
    if (ret && ret != E_FILE_EXIST)
		Check(ret, "Loading BEAMV1.PDD");
	}
	
	
LOCAL_C VOID CreateGC(VOID)                    /*  Create a graphics context  */
	{
	INT					hgc;

	hgc	=	gCreateGC0(MainWid);
	if (hgc	<	0)
		p_exit(hgc);
	}


LOCAL_C VOID SpecificInit(VOID)               /*  Application specific stuff  */
	{
	E_PROC					e;


	UnloadPDD();                                      /*  Unload just in case  */

	MainWid	=	uFindMainWid();
	
	WsrvHandle	=	p_pidfind("SYS$WSRV.*");               /*  Get ID of WServ  */
	p_getosd(&e, (VOID *)(p_getpid() & E_PIDMASK), sizeof(E_PROC));
	ioSem = e.semaphore;                            /*  Find our IO semaphore  */

	CreateGC();
	LoadPDD();
	CaptureKey();
	GoToBack();
	hCrackCommandLine();
	}
	

GLDEF_C VOID main(VOID)
	{
	uCommonInit();
	SpecificInit();
	MainLoop();
	}

